home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / EasyPHP-2.0b1-setup.exe / {app} / sqlitemanager / include / ParsingQuery.class.php < prev    next >
Encoding:
PHP Script  |  2006-04-18  |  16.4 KB  |  560 lines

  1. <?php
  2. /**
  3. * Web based SQLite management
  4. *
  5. * @package SQLiteManager
  6. * @author FrΘdΘric HENNINOT
  7. * @version $Id: ParsingQuery.class.php,v 1.41 2006/04/16 12:23:37 freddy78 Exp $ $Revision: 1.41 $
  8. */
  9.  
  10. class ParsingQuery {
  11.     /**
  12.     * Current Query
  13.     *
  14.     * @var string
  15.     * @access private
  16.     */
  17.     var $query;
  18.  
  19.     /**
  20.     * query formated type
  21.     * 1 = SQLite , 2 = MySQL
  22.     *
  23.     * @access private
  24.     * @var bool
  25.     */
  26.     var $type;
  27.  
  28.     /**
  29.     * All user string in an array
  30.     *
  31.     * @access private
  32.     * @var array
  33.     */
  34.     var $tabString;
  35.  
  36.     /**
  37.     * Query with format string included
  38.     *
  39.     * @access private
  40.     * @var string
  41.     */
  42.     var $formattedQuery;
  43.  
  44.     /**
  45.     * array of all query component
  46.     *
  47.     * @access private
  48.     * @var array
  49.     */
  50.     var $explodedQuery;
  51.  
  52.     /**
  53.     * Constructor of the class
  54.     *
  55.     * @param string $query Query string command
  56.     * @param int $type type export selector
  57.     */
  58.     function ParsingQuery($query, $type){
  59.         $this->query = $query;
  60.         $this->type = $type;
  61.     }
  62.  
  63.     /**
  64.     * Convert MySQL query to SQLite query
  65.     *
  66.     * @access public
  67.     */
  68.     function tabletoSQLite($query){
  69.         $query = eregi_replace('auto_increment=(.*)[[:space:]];', ';', $query);
  70.         $query = eregi_replace('[[:space:]]UNSIGNED[[:space:]]', ' ', $query);
  71.         $query = eregi_replace('TYPE=(.*)[[:space:]];', ';', $query);
  72.         $query = str_replace("\n", ' ', $query);
  73.         $startPar = strpos($query, '(');
  74.         $endPar = strrpos($query, ')');
  75.         preg_match('/TABLE[[:space:]](.*)[[:space:]]\(/i', substr($query, 0, ($startPar+1)), $result);
  76.         $tableName = ereg_replace('\[|\]','',$result[1]);
  77.         $tableElement = explode(',', substr($query, $startPar+1, ($endPar - $startPar)-1));
  78.         $numElement = 0;
  79.         $primaryExist = false;
  80.         while(list($key, $value)=each($tableElement)){
  81.             $numElement++;
  82.             if(eregi('not[[:space:]]null', $value)) {
  83.                 $matches = 'not[[:space:]]null';
  84.                 $defineElement[$numElement]['null'] = false;
  85.             }
  86.             if($matches) $value = eregi_replace($matches, '', $value);
  87.             if(!eregi('[[:space:]]key[[:space:]]', $value)){
  88.                 $value = $this->bracketsReplaceSpaces($value,'@ñ&');
  89.                 $tabValue = explode(' ', trim($value));
  90.                 $tabValue[0] = str_replace('@ñ&',' ',$tabValue[0]);
  91.                 $defineElement[$numElement]['name'] = trim($tabValue[0]);
  92.                 if(eregi('auto_increment', trim($value))){
  93.                     $defineElement[$numElement]['type'] = 'INTEGER';
  94.                     $defineElement[$numElement]['sup'] = 'PRIMARY KEY';
  95.                     $primaryExist = true;
  96.                     continue;
  97.                 }                
  98.                 $defineElement[$numElement]['type'] = str_replace(' int(', ' INTEGER(', $tabValue[1]);    
  99.                 for($i = 2 ; $i<count($tabValue) ; $i++) {
  100.                     if (eregi('zerofill[ ]?',$tabValue[$i])) {
  101.                         $tabValue[$i] = eregi_replace('zerofill[ ]?','',$tabValue[$i]);
  102.                         //$defineElement[$numElement]['type'] .= ' zerofill';
  103.                     }
  104.                     if(!isset($defineElement[$numElement]['sup'])) $defineElement[$numElement]['sup']='';
  105.                     $defineElement[$numElement]['sup'] .= $tabValue[$i].' ';
  106.                 }
  107.                 if(eregi('set|enum', $tabValue[1])){
  108.                     if(!ereg('\)', $tabValue[1])){
  109.                         for($i=($key+1) ; $i<= (count($tableElement)+1) ; $i++) {
  110.                             $tabValue[1] .= ','.$tableElement[$i];
  111.                             unset($tableElement[$i]);
  112.                             if(ereg('\)', $tabValue[1])) break;
  113.                         }
  114.                     }
  115.                     preg_match('/\((.*)\)/i', $tabValue[1], $enumRes);
  116.                     $tabPropEnum = explode(',', $enumRes[1]);
  117.                     $maxlen = 0;
  118.                     foreach($tabPropEnum as $propEnum) if(strlen($propEnum)>$maxlen) $maxlen = strlen($propEnum);
  119.                     $defineElement[$numElement]['type'] = 'varchar('.($maxlen-2).')';
  120.  
  121.                     preg_match('/\)(.*)/', $tabValue[1], $supRes);
  122.                     $defineElement[$numElement]['type'] .= $supRes[1];
  123.                 }
  124.             } else {
  125.                 if(!ereg('\)', $value)){
  126.                     for($i=($key+1) ; $i<= (count($tableElement)+1) ; $i++) {
  127.                         $value .= ','.$tableElement[$i];
  128.                         unset($tableElement[$i]);
  129.                         if(ereg('\)', $value)) break;
  130.                     }
  131.                 }
  132.                 if(isset($tabIndex)) $numIndex = count($tabIndex)+1;
  133.                 else $numIndex = 1;
  134.                 preg_match('/key(.*)\(/i', $value, $indexSearch);
  135.                 $indexName = ereg_replace('\[|\]','',trim($indexSearch[1]));
  136.                 if(eregi('PRIMARY', $value) && !$primaryExist) {
  137.                     $listChamp = $this->recupFields($value);
  138.                     if(is_array($listChamp)) {
  139.                         $tabIndex[$numIndex]['type'] = 'UNIQUE';
  140.                         $tabIndex[$numIndex]['champ'] = $listChamp;
  141.                         $tabIndex[$numIndex]['name'] = $indexName;
  142.                     } else {
  143.                         $listElem = $defineElement;
  144.                         while(list($key, $value) = each($listElem)){
  145.                             if($value['name']==$listChamp) $defineElement[$key]['sup'] .=' PRIMARY KEY';
  146.                         }
  147.                     }
  148.                 } elseif(!eregi('PRIMARY', $value)) {
  149.                     if(eregi('UNIQUE', $value)) $tabIndex[$numIndex]['type'] = 'UNIQUE';
  150.                     $listChamp = $this->recupFields($value);
  151.                     $tabIndex[$numIndex]['champ'] = $listChamp;
  152.                     $tabIndex[$numIndex]['name'] = $indexName;
  153.                 }                
  154.             }
  155.         }
  156.  
  157.         $finaleQuery = 'CREATE TABLE '.brackets($tableName).' ('."\n";
  158.         foreach($defineElement as $elem) {
  159.             $column[] = brackets($elem['name']).' '.$elem['type'].((isset($elem['null']) && !$elem['null'])? ' NOT NULL ' : ' ' ).$elem['sup'];
  160.         }
  161.         $finaleQuery .= "\t".implode(",\n\t", $column)."\n);";
  162.         $tabQ[] = $finaleQuery;
  163.         if(isset($tabIndex) && is_array($tabIndex)){
  164.             foreach($tabIndex as $ind){
  165.                 $query = 'CREATE';
  166.                 if($ind['type']) $query .= ' '.$ind['type'];
  167.                 if (is_array($ind['champ'])) {
  168.                     foreach ($ind['champ'] as $key=>$champ) $ind['champ'][$key] = brackets($champ);
  169.                     $columns = implode(',', $ind['champ']);
  170.                 } else
  171.                     $columns = brackets($ind['champ']);                 
  172.                 $query .= ' INDEX '. str_replace(' ','_',$tableName.'_'.$ind['name']).' ON '.brackets($tableName).' ('.$columns.');';
  173.                 $tabQ[] = $query;
  174.             }
  175.         }
  176.         return $tabQ;
  177.     }
  178.  
  179.     /**
  180.     *  Convert MySQL brackets in query when spaces in objects
  181.     *
  182.     * @access public
  183.     */
  184.     function convertBrackets($query){ 
  185.         $query = str_replace('\`','@ñ&',$query);
  186.         
  187.         //Force brackets conversion even if no spaces in object name (for bracket tests)
  188.         $force = false;
  189.         
  190.         $d = $p = 0; $in = false;
  191.         while ($p = strpos("-$query",'`',$p)) {
  192.             $in = (!$in);
  193.  
  194.             if (!$in) {
  195.                 $object = substr($query,$d,$p-$d-1);
  196.                 if (strpos("-$object",' ') || $force)
  197.                     $query = substr($query,0,$d-1)."[$object]".substr($query,$p);
  198.                 else {
  199.                     $query = substr($query,0,$d-1).$object.substr($query,$p);
  200.                     $p-=2;
  201.                 }
  202.             }
  203.             $d = $p;
  204.             $p++;
  205.         }
  206.  
  207.         return str_replace('@ñ&','`',$query);
  208.     }
  209.     
  210.     /**
  211.     *  Replace spaces in brackets, usefull before split(' ',$query)
  212.     *
  213.     * @access public
  214.     */
  215.     function bracketsReplaceSpaces($query,$replaceBy) {
  216.         if (strstr($query,'[')) {
  217.             //regex : objects between brackets
  218.             if (preg_match_all('#\[([^\]]*)?\]#',$query,$matches,PREG_SET_ORDER))
  219.                 foreach ($matches as $matche)
  220.                     if (strstr($matche[1],' ')) {
  221.                         $object = str_replace(' ',$replaceBy,$matche[0]);
  222.                         $query = str_replace($matche[0],$object,$query);                        
  223.                     }
  224.         }
  225.         return $query;
  226.     }
  227.  
  228.     /**
  229.     *  Split, Clean and Convert query!!
  230.     *
  231.     * @access public
  232.     */
  233.     function convertQuery(){
  234.         $localQuery = $this->query;
  235.         $localQuery = str_replace("\r\n", "\n", $localQuery);
  236.         $localQuery = ereg_replace("/;?\n/", ";\n", $localQuery);
  237.         if($this->type == 2){    
  238.             $localQuery = str_replace("\\'", "''", $localQuery);
  239.             $localQuery = preg_replace("/^use.*\n/i", '', $localQuery);
  240.             $localQuery = $this->convertBrackets($localQuery);
  241.         }
  242.  
  243.         $localQuery = $this->purgeComment($localQuery);
  244.         if(strpos($localQuery, ";\n")){
  245.             $tabQuery = explode(";\n", $localQuery);
  246.             $tabOut = array();
  247.             $startTrigger = false;
  248.             $tempQueryString = '';
  249.             while(list($key, $req) = each($tabQuery)) {
  250.                 if(empty($req)) continue;
  251.                 if(!$startTrigger && eregi('/^'.implode('|', $GLOBALS['elementStartQuery']).'/', $req)) {
  252.                     // starting new query
  253.                     if(!empty($tempQueryString)) {
  254.                         if(substr($tempQueryString, -1)!=';') $tempQueryString .= ';';
  255.                             $tabOut[] = $tempQueryString;
  256.                             $tempQueryString = '';                
  257.                     }                    
  258.                 }
  259.                 if($this->type == 1){
  260.                     if(eregi('begin[[:space:]]transaction', $req)) continue;
  261.                     if(eregi('commit|transaction', $req)) continue;
  262.                     if(eregi('create[[:space:]]trigger', $req)) {
  263.                         $startTrigger = true;
  264.                         $queryTrigger = '';
  265.                     }
  266.                     if(!$startTrigger) {
  267.                         $tempQueryString .= $req;
  268.                     } else {
  269.                         $queryTrigger .= ' '.$req;
  270.                         if(substr($req, -1)!=';') $queryTrigger .= ';';
  271.                         if(eregi('end$', trim($req))) {
  272.                             $startTrigger = false;
  273.                             $tabOut[] = str_replace("\n", ' ', $queryTrigger);
  274.                         }
  275.                     }
  276.                 } elseif($this->type == 2) {
  277.                     $req = str_replace("\\r\\n", "\n", $req);
  278.                     if(ereg('^--', $req)) continue;
  279.                     if(eregi('[[:space:]]IF EXISTS[[:space:]]', $req)) continue;
  280.                     if(eregi('create[[:space:]]table', $req)) {
  281.                         $tabTable = $this->tabletoSQLite(str_replace("\n", ' ', $req));
  282.                         $tabOut = array_merge($tabOut, $tabTable);
  283.                         $tempQueryString = '';
  284.                     } else {
  285.                         $tempQueryString .= $req;
  286.                     }
  287.                 }
  288.             }
  289.             if(!empty($tempQueryString)) {
  290.                 if(substr($tempQueryString, -1)!=';') $tempQueryString .= ';';
  291.                 $tabOut[] = $tempQueryString;
  292.             }
  293.             return $tabOut;
  294.         } else {
  295.             if($this->type==2){
  296.                 if(eregi('CREATE[[:space:]]TABLE', $localQuery)) $localQuery = $this->tabletoSQLite($localQuery);
  297.                 $localQuery = str_replace("\\r\\n", "\n", $localQuery);
  298.             }
  299.             return $localQuery;
  300.         }
  301.     }
  302.  
  303.     /**
  304.     * Retreive champ name from sql list
  305.     *
  306.     * @access private
  307.     * @param string $string is the string into SELECT and FROM
  308.     */
  309.     function recupFields($string){
  310.         $string = ereg_replace('\[|\]','',$string);
  311.         preg_match('/\((.*)\)/', $string, $parChamp);
  312.         if(strpos($parChamp[1], ',')) $listChamp = explode(',', $parChamp[1]);
  313.         else $listChamp = trim($parChamp[1]);
  314.         return $listChamp;
  315.     }
  316.  
  317.     /**
  318.     * Clean query's comment
  319.     *
  320.     * @access public
  321.     * @param string $query query
  322.     */
  323.     function purgeComment($query){
  324.         $tabQ = explode("\n", $query);
  325.         $commentBlock = false;
  326.         $outQ = array();
  327.         if(is_array($tabQ)){
  328.             foreach($tabQ as $lineQ){
  329.                 if(eregi('\/\*', $lineQ)) $commentBlock = true;
  330.                 if( !$commentBlock && (substr(trim($lineQ), 0, 1)!= '#') && (substr(trim($lineQ), 0, 2)!= '--') && !empty($lineQ)) {
  331.                     $outQ[] = $lineQ;
  332.                 }
  333.                 if(eregi('\*\/', $lineQ)) $commentBlock = false;
  334.             }
  335.             $query = implode("\n", $outQ);
  336.         }
  337.         return $query;
  338.     }
  339.  
  340.     /**
  341.     * recup query without limit
  342.     *
  343.     * @access public
  344.     * @param string $query query
  345.     */
  346.     function noLimit($query){
  347.         if(eregi('LIMIT[[:space:]]', $query)){
  348.             preg_match('/LIMIT(.*),/i', $query, $limitRes);
  349.             if(isset($limitRes[1])) {
  350.                 $startRecLimit = (int)(trim($limitRes[1]));
  351.                 $out['page'] = ($startRecLimit / BROWSE_NB_RECORD_PAGE) +1;
  352.                 $out['query'] = eregi_replace('LIMIT.*', '', $query);
  353.             }
  354.         } else {
  355.             $out['query'] = $query;
  356.             $out['page'] = '';
  357.         }
  358.         return $out;
  359.     }
  360.  
  361.     /**
  362.     * extract all query properties
  363.     *
  364.     * @access private
  365.     * @ param string $query query
  366.     */
  367.     function explodeQuery($query=''){
  368.         if($query == '') $query = $this->query;
  369.         $query = $this->formattedQuery = ereg_replace("''", '#%úQú%#', $query);
  370.         $tabQuote = strpos_all($query, "'");
  371.         $inString = false;
  372.         $this->tabString = array();
  373.         $stringNumber = 0;
  374.         if(is_array($tabQuote)){
  375.             while(list($key, $posQuote) = each($tabQuote)){
  376.                 if(!$inString){
  377.                     $start = $posQuote;
  378.                     $stringNumber++;
  379.                     $inString = true;
  380.                 } else {
  381.                     $end = $posQuote;
  382.                     $subQuery = substr($query, $start, ($end-$start)+1);
  383.                     $this->tabString[$stringNumber] = ereg_replace('#%úQú%#', "''",  $subQuery);
  384.                     $this->formattedQuery = str_replace($subQuery, '#%ú'.$stringNumber.'ú%#', $this->formattedQuery);
  385.                     $inString = false;
  386.                 }
  387.             }
  388.         }
  389.         $this->formattedQuery = str_replace("\t", '', $this->formattedQuery);
  390.         $tabExplodedQuery = split('[[:space:]]+', $this->formattedQuery);
  391.         $tabOut = array();
  392.         foreach($tabExplodedQuery as $once){
  393.             if(eregi('['.preg_quote($GLOBALS['SQLpunct']).']', $once)){
  394.                 $once = preg_replace('/['.preg_quote($GLOBALS['SQLpunct']).']/', ' $0 ', $once);
  395.                 $tempTab = explode(" ",$once);
  396.                 $tabOut = array_merge($tabOut, $tempTab);
  397.             } else {
  398.                 $tabOut[] = $once;
  399.             }
  400.         }
  401.         $this->explodedQuery = $tabOut;
  402.         return;
  403.     }
  404.  
  405.     /**
  406.     * Colorize SQL
  407.     *
  408.     * @access private
  409.     */
  410.     function colorWordList(){
  411.         $indent = $braketLevel = 0;
  412.         foreach($this->explodedQuery as $key=>$value){
  413.             if(($value == '') || (ereg('#%ú(.*)ú%#', $value))) continue;
  414.             $currentWord = strtoupper(trim($value));
  415.             $tabWord = array_merge($GLOBALS['SQLKeyWordList'], $GLOBALS['SQLoperator']);
  416.             if(eregi("[".preg_quote($GLOBALS['SQLpunct']).']', $currentWord)){
  417.                 $value = $this->explodedQuery[$key] = preg_replace('/['.preg_quote($GLOBALS['SQLpunct']).']/', "<span class=\"syntaxe_punct\">$0</span>", $value);
  418.             }
  419.             if(in_array($currentWord, $tabWord)){
  420.                 $this->explodedQuery[$key] = $this->colorizeWord($value, $currentWord, 'syntaxe_keyword');
  421.             } elseif(in_array($currentWord, $GLOBALS['SQLfunction'])){
  422.                 $this->explodedQuery[$key] = $this->colorizeWord($value, $currentWord, 'syntaxe_function');
  423.             } elseif(($currentWord != '0') && in_array($currentWord, $GLOBALS['SQLiteType'])){
  424.                 $this->explodedQuery[$key] = $this->colorizeWord($value, $currentWord, 'syntaxe_type');
  425.             } elseif(ereg('[0-9]+', trim($value))){
  426.                 $this->explodedQuery[$key] = $this->colorizeWord($value, trim($value), 'syntaxe_digit');
  427.             } elseif(eregi('[0-9a-z]+', trim($value))){
  428.                 $this->explodedQuery[$key] = $this->colorizeWord($value, trim($value), 'syntaxe_variable');
  429.             } else {
  430.                 $this->explodedQuery[$key] = $this->colorizeWord($value, trim($value), 'syntaxe_variable');
  431.             }
  432.             $braketOk = false;
  433.             $tabBraket = array();
  434.             if(ereg('\(', $currentWord)) {
  435.                 $braketStart = true;
  436.                 $braketLevel++;
  437.                 if($braketOk) {
  438.                     $indent++;
  439.                     $tabBraket[] = $braketLevel;
  440.                     $braketOk = false;
  441.                     $this->explodedQuery[$key] = $this->explodedQuery[$key].'<div style="margin-left: '.$indent.'em;">';
  442.                 }
  443.             }
  444.             if(ereg('\)', $currentWord)) {
  445.                 $braketEnd = true;
  446.                 if(is_array($tabBraket) && in_array($braketLevel, $tabBraket)){
  447.                     $this->explodedQuery[$key] = '</div>'.$this->explodedQuery[$key];
  448.                     $indent--;
  449.                 }
  450.                 $braketLevel--;
  451.             }
  452.             /*
  453.             if(ereg(',', $currentWord)){
  454.                 $this->explodedQuery[$key] = $this->explodedQuery[$key].'<br/>';
  455.             }
  456.             */
  457.             $DownIndent = $UpIndent = false;
  458.             $outString = "";
  459.             switch ($currentWord) {
  460.                 case 'CREATE':
  461.                     $DownIndent = true;
  462.                     $outString = '<br/>'.$this->explodedQuery[$key];
  463.                     $braketOk = true;
  464.                     break;
  465.                 case 'EXPLAIN':
  466.                 case 'DESCRIBE':
  467.                 case 'SET':
  468.                 case 'DELETE':
  469.                 case 'SHOW':
  470.                 case 'DROP':
  471.                 case 'UPDATE':
  472.                 case 'ANALYZE':
  473.                 case 'ANALYSE':
  474.                 case 'LIMIT':
  475.                 case 'SELECT':
  476.                 case 'FROM':
  477.                 case 'WHERE':
  478.                 case 'LEFT':
  479.                 case 'RIGHT':
  480.                 case 'INNER':
  481.                 case 'GROUP':
  482.                 case 'ORDER':
  483.                 case 'INSERT':
  484.                 case 'REPLACE':
  485.                 case 'VALUES':
  486.                 case 'END':
  487.                     $DownIndent = true;
  488.                     $outString = '<br/>'.$this->explodedQuery[$key];
  489.                     break;
  490.                 default:
  491.                     break;
  492.             }
  493.             if($DownIndent){
  494.                     if($indent){
  495.                         $indent--;
  496.                         $this->explodedQuery[$key] = '</div>'.$this->explodedQuery[$key];
  497.                     }
  498.             }
  499.             if($outString){
  500.                 $this->explodedQuery[$key] = $outString;
  501.             }
  502.             if($UpIndent){
  503.                     $indent++;
  504.             }
  505.         }
  506.         if($indent){
  507.             for($i=$indent; $i>0 ; $i--) $this->explodedQuery[] = '</div>';
  508.         }
  509.     }
  510.  
  511.     /**
  512.     * Colorize aword
  513.     * replace word into a string with the word colorized
  514.     *
  515.     * @access public
  516.     * @param string $string The start string
  517.     * @param string $word The word who must be colorized
  518.     * @param string $className The style classname for colorize word
  519.     * @return string
  520.     */
  521.     function colorizeWord($string, $word, $className){
  522.         $newWord = '<span class="'.$className.'">'.$word.'</span>';
  523.         return eregi_replace(preg_quote($word), $newWord, $string);
  524.     }
  525.  
  526.     /**
  527.     * Displaying Highlighted Query
  528.     *
  529.     * @access private
  530.     */
  531.     function highlightQuery(){
  532.         $query = implode(' ', $this->explodedQuery);
  533.         $query = eregi_replace('#%úQú%#', '<span class="syntaxe_string">'."''".'</span>', $query);
  534.         foreach($this->tabString as $key=>$value) $query = eregi_replace('#%ú'.$key.'ú%#', '<span class="syntaxe_string">'.htmlentities($value, ENT_NOQUOTES, $GLOBALS['charset']).'</span>', $query);
  535.  
  536.         if(strpos($query, '<br/>') === 0) $query = substr($query, 5, strlen($query)-4);
  537.         return $query;
  538.     }
  539.  
  540.     /**
  541.      *
  542.      *
  543.      */
  544.     function explodeSelect($query){
  545.         $tabClause = array('SELECT', 'FROM', 'WHERE', 'GROUP BY', 'HAVING', 'ORDER BY', 'LIMIT');
  546.         $tabElement = array();
  547.         $i = 0;
  548.         foreach($tabClause as $selectElem) {
  549.             if(eregi($selectElem, $query)){
  550.                 $tabElement[$i++] = $selectElem;
  551.             }
  552.         }
  553.         $tabResult = preg_split('/'.implode('|', array_values($tabElement)).'/', $query);
  554.         $out = array();
  555.         foreach($tabElement as $key=>$clause) if($key>=0) $out[$clause] = trim($tabResult[$key+1]);
  556.         return $out;
  557.     }
  558. }
  559. ?>
  560.